package com.client;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Client {

	private static final String NICKNAMEW_VALID = "nickvalid";
	private static final Object DISCONNECT = "bye";
	private String name;
	private String serverHost;
	private int serverPort;
	private BufferedWriter writer;
	private BufferedReader reader;
	private Socket socket;

	protected Socket connect() {
		try {
			socket = new Socket(InetAddress.getByName(serverHost), serverPort);
			System.out.println("connect successfully!");
			writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8));
			reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
		} catch (IOException e) {
			// e.printStackTrace();
			System.out.println(e.getMessage());
			System.exit(0);
		}
		return socket;
	}

	protected void send(String message) {
		try {
			writer.write(message + "\n");
			writer.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void chat() {
		connect();
		setNickName();
		receiveToStdout();
		while (true) {
			BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
			String msg;
			try {
				msg = r.readLine();
				send(msg);
				if (msg.equals(DISCONNECT)) {
					disConnect();
					break;
				}
			} catch (IOException e) {
				e.printStackTrace();
			}

		}
	}

	protected String receive() {
		String result = "";
		Callable<String> task = () -> {
			String line = "";
			while ((line = reader.readLine()) != null) {
				return line;
			}
			return line;
		};
		FutureTask<String> f = new FutureTask<>(task);
		new Thread(f).start();
		try {
			result = f.get();
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		}
		return result;
	}

	protected void receiveToStdout() {
		new Thread(() -> {
			String line = "";
			try {
				while (!socket.isClosed() && (line = reader.readLine()) != null) {
					System.out.println(line);
				}
			} catch (Exception e) {
				if (!socket.isClosed())
					e.printStackTrace();
			}
		}).start();
	}

	protected void disConnect() {
		System.out.println("disconnect.");
		try {
			if (!socket.isClosed())
				socket.close();
			reader.close();
			writer.close();
		} catch (IOException e) {
			// e.printStackTrace();
			System.out.println(e.getMessage());
		}
	}

	protected void setNickName() {
		System.out.println("Enter your nick name:");
		@SuppressWarnings("resource")
		Scanner in = new Scanner(System.in);
		while (in.hasNextLine()) {
			String name = in.nextLine();
			send(name);
			String result;
			try {
				result = reader.readLine();
				if (result.equals(NICKNAMEW_VALID)) {
					this.setName(name);
					break;
				}
			} catch (IOException e) {
				e.printStackTrace();
			}

			System.out.println("nick name is already existed,please enter again:");
		}
	}

	public String getName() {
		return name;
	}

	private void setName(String name) {
		this.name = name;
	}

	public String getServerHost() {
		return serverHost;
	}

	public void setServerHost(String serverHost) {
		this.serverHost = serverHost;
	}

	public int getServerPort() {
		return serverPort;
	}

	public void setServerPort(int serverPort) {
		this.serverPort = serverPort;
	}

	public BufferedWriter getWriter() {
		return writer;
	}

	public BufferedReader getReader() {
		return reader;
	}

}
